(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['exports'], factory);
    } else if (typeof module === 'object' && module.exports) {
        module.exports = factory(exports);
    } else {
        root.InflateZlib = factory();
    }
}(typeof self !== 'undefined' ? self : this, function () {
    var InflateZlib = function(streamOrWindowBits, windowBits) {
        if (typeof streamOrWindowBits === 'number') {
            this.windowBits = streamOrWindowBits;
        }
        else {
            this.stream = streamOrWindowBits;
            this.windowBits = windowBits;
        }
    }
    InflateZlib.prototype = {}

    InflateZlib.prototype.READ_CHUNK_SIZE = 4096
    /**
     * Inflates the given bytes.
     * This is technically the same as the `pako.inflate()` wrapper, except we throw real errors instead of strings.
     * @param bytes The bytes to inflate.
     * @returns The inflated bytes.
     */
    InflateZlib.prototype.decodeBytes = function(bytes, windowBits) {
        const inflate = new pako.Inflate({ windowBits, raw: windowBits < 0 });
        // Write all the bytes
        inflate.push(bytes, true);
        // Check for errors
        if (inflate.err !== pako.Z_OK)
            throw new Error(`Pako error: ${inflate.err} ${inflate.msg}`);
        // Return the inflated data
        return inflate.result;
    }

    /**
     * Inflates the stream.
     * @returns The inflated bytes.
     */
    InflateZlib.prototype.decodeStream = function(stream, windowBits) {
        const inflate = new pako.Inflate({ windowBits, raw: windowBits < 0 });
        // Read `stream` until one of the stream ends
        while (!inflate.ended && !stream.isEof()) {
            const available = stream.size - stream.pos;
            const readSize = Math.min(available, this.READ_CHUNK_SIZE);
            inflate.push(stream.readBytes(readSize));
        }
        // Check for errors
        if (inflate.err !== 0)
            throw new Error(`Pako error: ${inflate.err} ${inflate.msg}`);
        // Reset the stream position to the end of the zlib stream
        stream.seek(stream.pos - inflate.strm.avail_in);
        // Return the inflated data
        return inflate.result;
    }

    /**
     * Inflates the Kaitai stream.
     * @param data The data to inflate. If there is no data and a stream was provided in the constructor, the stream is used instead.
     * @returns The inflated data.
     */
    InflateZlib.prototype.decode = function(data) {
        var _a;
        let windowBits = (_a = this.windowBits) !== null && _a !== void 0 ? _a : 15;
        if (windowBits < 0)
            windowBits = -windowBits;
        while (windowBits > 15)
            windowBits = windowBits - 16;
        if (this.stream)
            return (0, this.decodeStream)(this.stream, windowBits);
        else if (data.length)
            return (0, this.decodeBytes)(data, windowBits);
        else
            return new Uint8Array(0);
    }

    return InflateZlib;
}));
